package com.ziiwee.reduce.rest.condition.parser;

import com.ziiwee.reduce.commons.utils.StringUtil;
import com.ziiwee.reduce.rest.condition.Condition;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * AbstractConditionParser
 *
 * @author ziiwee
 * @date 2020/5/29
 */
public abstract class AbstractQLConditionParser implements ConditionParser<String> {

    protected final Map<String, String> STRING_VALUES_MAP = new HashMap<>();

    protected final Map<String, Condition> PARENTHESIS_MAP = new HashMap<>();

    protected Class<?> modelType;

    public AbstractQLConditionParser(Class<?> modelType) {
        this.modelType = modelType;
    }

    public Condition parse(String ql) throws ConditionParserException {
        if(!StringUtil.hasLength(ql)){
            return null;
        }
        ql = parseStringValue(ql);
        ql = parseParenthesis(ql);
        Condition condition = parseLogicCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = parseBetweenCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = parseComparableCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = parseEqualCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = parseLikeCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = parseNullCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = parseInCondition(ql);
        if (condition != null) {
            return condition;
        }
        condition = PARENTHESIS_MAP.get(ql);
        if (condition != null) {
            return condition;
        }
        throw new ConditionParserException(String.format("无法解析表达式：%s", ql));
    }

    protected String parseStringValue(String ql) {
        ql = ql.trim();
        int index1 = ql.indexOf("'");
        int index2 = ql.indexOf("\"");
        if (index1 < 0 && index2 < 0) {
            return ql;
        }
        String symbol = index1 < 0 ? "\"" : "'";
        int start = ql.indexOf(symbol) + 1;
        String value = ql.substring(start, ql.indexOf(symbol, start));
        String id = createStringValueId();
        STRING_VALUES_MAP.put(id, value);
        String newQl = ql.replaceAll(symbol + value + symbol, id);
        return parseStringValue(newQl);
    }

    protected String parseParenthesis(String ql) {
        int inLeft = ql.lastIndexOf("(");
        if (inLeft < 0) {
            return ql;
        }
        int inRight = ql.indexOf(")", inLeft);
        String parenthesis = ql.substring(inLeft, inRight + 1);
        String parenthesisQl = ql.substring(inLeft + 1, inRight);
        Condition condition = parse(parenthesisQl);
        String id = "";
        if (condition != null) {
            id = createParenthesisId();
            PARENTHESIS_MAP.put(id, condition);
        }
        String newQl = ql.replace(parenthesis, id);
        return parseParenthesis(newQl);
    }

    protected String reductionStringValue(String value) {
        String s = STRING_VALUES_MAP.get(value.trim());
        return StringUtils.hasLength(s) ? s : value;
    }

    protected String createStringValueId() {
        return String.format("%s_%s_%s", "STRING_VALUE_ID_PREFIX", STRING_VALUES_MAP.size(), System.currentTimeMillis());
    }

    protected String createParenthesisId() {
        return String.format("%s_%s_%s", "PARENTHESIS_ID_PREFIX", PARENTHESIS_MAP.size(), System.currentTimeMillis());
    }

    protected abstract Condition parseLogicCondition(String ql);

    protected abstract Condition parseBetweenCondition(String ql);

    protected abstract Condition parseComparableCondition(String ql);

    protected abstract Condition parseEqualCondition(String ql);

    protected abstract Condition parseInCondition(String ql);

    protected abstract Condition parseLikeCondition(String ql);

    protected abstract Condition parseNullCondition(String ql);


}
